home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / prospero / propsero.lha / prospero-beta.4.2e / user / aquery.c < prev    next >
C/C++ Source or Header  |  1992-02-10  |  7KB  |  239 lines

  1. /*
  2.  * aquery.c : Programmatic Prospero interface to Archie
  3.  *
  4.  * Copyright (c) 1991 by the University of Washington
  5.  *
  6.  * For copying and distribution information, please see the file
  7.  * <uw-copyright.h>.
  8.  *
  9.  * Originally part of the Prospero Archie client by Clifford 
  10.  * Neuman (bcn@isi.edu).  Modifications, addition of programmatic interface,
  11.  * and new sorting code by George Ferguson (ferguson@cs.rochester.edu) 
  12.  * and Brendan Kehoe (brendan@cs.widener.edu).
  13.  *
  14.  *  - bcn 08/20/91 - make it do it properly (new invdatecmplink)
  15.  *  - bpk 08/20/91 - made sorting go inverted as we purport it does
  16.  */
  17. #include <uw-copyright.h>
  18.  
  19. #include <stdio.h>
  20. #include <strings.h>            /* for char *index() */
  21.  
  22. #include <pfs.h>
  23. #include <perrno.h>
  24. #include <pmachine.h>
  25. #include <archie.h>
  26.  
  27. static void translateArchieResponse();
  28.  
  29. /*
  30.  * archie_query : Sends a request to _host_, telling it to search for
  31.  *                _string_ using _query_type_ as the search method.
  32.  *                No more than _max_hits_ matches are to be returned
  33.  *                skipping over _offset_ matches.
  34.  *
  35.  *          archie_query returns a linked list of virtual links. 
  36.  *                If _flags_ does not include AQ_NOTRANS, then the Archie
  37.  *                responses will be translated. If _flags_ does not include 
  38.  *                AQ_NOSORT, then the list will be sorted using _cmp_proc_ to
  39.  *                compare pairs of links.  If _cmp_proc_ is NULL or AQ_DEFCMP,
  40.  *                then the default comparison procedure, defcmplink(), is used
  41.  *                sorting by host, then filename. If cmp_proc is AQ_INVDATECMP
  42.  *                then invdatecmplink() is used, sorting inverted by date.
  43.  *                otherwise a user-defined comparison procedure is called.
  44.  *
  45.  *                archie_query returns NULL and sets perrno if the query
  46.  *                failed. Note that it can return NULL with perrno == PSUCCESS
  47.  *                if the query didn't fail but there were simply no matches.
  48.  *
  49.  *   query_type:  S  Substring search ignoring case   
  50.  *                C  Substring search with case significant
  51.  *                R  Regular expression search
  52.  *                =  Exact String Match
  53.  *            s,c,e  Tries exact match first and falls back to S, C, or R 
  54.  *                   if not found.
  55.  *
  56.  *     cmp_proc:  AQ_DEFCMP      Sort by host, then filename
  57.  *                AQ_INVDATECMP  Sort inverted by date
  58.  *
  59.  *        flags:  AQ_NOSORT      Don't sort results
  60.  *                AQ_NOTRANS     Don't translate results
  61.  */
  62. VLINK 
  63. archie_query(host,string,max_hits,offset,query_type,cmp_proc,flags)
  64.     char    *host,*string;
  65.     int        max_hits,offset;
  66.     char    query_type;
  67.     int        (*cmp_proc)();
  68.     int        flags;
  69.     {
  70.     char qstring[MAX_VPATH];    /* For construting the query  */
  71.     VLINK    links;        /* Matches returned by server */
  72.     VDIR_ST    dir_st;         /* Filled in by get_vdir      */
  73.     VDIR    dir= &dir_st;
  74.     
  75.     VLINK    p,q,r,lowest,nextp,pnext,pprev;
  76.     int    tmp;
  77.  
  78.     /* Set the cmp_proc if not given */
  79.     if (cmp_proc == NULL) cmp_proc = defcmplink;
  80.  
  81.     /* Make the query string */
  82.     sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s",
  83.         max_hits,offset,query_type,string);
  84.  
  85.     /* Initialize Prospero structures */
  86.     perrno = 0; *p_err_string = '\0';
  87.     vdir_init(dir);
  88.     
  89.     /* Retrieve the list of matches, return error if there was one */
  90.     if(tmp = get_vdir(host,qstring,"",dir,GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) {
  91.         perrno = tmp;
  92.         return(NULL);
  93.     }
  94.  
  95.     /* Save the links, and clear in dir in case it's used again   */
  96.     links = dir->links; dir->links = NULL;
  97.  
  98.     /* As returned, list is sorted by suffix, and conflicting     */
  99.     /* suffixes appear on a list of "replicas".  We want to       */
  100.     /* create a one-dimensional list sorted by host then filename */
  101.     /* and maybe by some other parameter                          */
  102.  
  103.     /* First flatten the doubly-linked list */
  104.     for (p = links; p != NULL; p = nextp) {
  105.         nextp = p->next;
  106.         if (p->replicas != NULL) {
  107.         p->next = p->replicas;
  108.         p->next->previous = p;
  109.         for (r = p->replicas; r->next != NULL; r = r->next)
  110.             /*EMPTY*/ ;
  111.         r->next = nextp;
  112.         nextp->previous = r;
  113.         p->replicas = NULL;
  114.         }
  115.     }
  116.  
  117.     /* Translate the filenames unless NOTRANS was given */
  118.     if (!(flags & AQ_NOTRANS))
  119.         for (p = links; p != NULL; p = p->next)
  120.         translateArchieResponse(p);
  121.  
  122.     /* If NOSORT given, then just hand it back */
  123.     if (flags & AQ_NOSORT) {
  124.         perrno = PSUCCESS;
  125.         return(links);
  126.     }
  127.  
  128.     /* Otherwise sort it using a selection sort and the given cmp_proc */
  129.     for (p = links; p != NULL; p = nextp) {
  130.         nextp = p->next;
  131.         lowest = p;
  132.         for (q = p->next; q != NULL; q = q->next)
  133.         if ((*cmp_proc)(q,lowest) < 0)
  134.             lowest = q;
  135.         if (p != lowest) {
  136.         /* swap the two links */
  137.         pnext = p->next;
  138.         pprev = p->previous;
  139.         if (lowest->next != NULL)
  140.             lowest->next->previous = p;
  141.         p->next = lowest->next;
  142.         if (nextp == lowest) {
  143.             p->previous = lowest;
  144.         } else {
  145.             lowest->previous->next = p;
  146.             p->previous = lowest->previous;
  147.         }
  148.         if (nextp == lowest) {
  149.             lowest->next = p;
  150.         } else {
  151.             pnext->previous = lowest;
  152.             lowest->next = pnext;
  153.         }
  154.         if (pprev != NULL)
  155.             pprev->next = lowest;
  156.         lowest->previous = pprev;
  157.         /* keep the head of the list in the right place */
  158.         if (links == p)
  159.             links = lowest;
  160.         }
  161.     }
  162.  
  163.     /* Return the links */
  164.     perrno = PSUCCESS;
  165.     return(links);
  166.     }
  167.  
  168. /*
  169.  * translateArchieResponse: 
  170.  *
  171.  *   If the given link is for an archie-pseudo directory, fix it. 
  172.  *   This is called unless AQ_NOTRANS was given to archie_query().
  173.  */
  174. static void
  175. translateArchieResponse(l)
  176.     VLINK l;
  177.     {
  178.     char *slash;
  179.  
  180.     if (strcmp(l->type,"DIRECTORY") == 0) {
  181.         if (strncmp(l->filename,"ARCHIE/HOST",11) == 0) {
  182.         l->type = stcopyr("EXTERNAL(AFTP,DIRECTORY)",l->type);
  183.         l->host = stcopyr(l->filename+12,l->host);
  184.         slash = index(l->host,'/');
  185.         if (slash) {
  186.             l->filename = stcopyr(slash,l->filename);
  187.             *slash++ = '\0';
  188.         } else
  189.             l->filename = stcopyr("",l->filename);
  190.         }
  191.     }
  192.     }
  193.  
  194. /*
  195.  * defcmplink: The default link comparison function for sorting. Compares
  196.  *           links p and q first by host then by filename. Returns < 0 if p
  197.  *             belongs before q, > 0 if p belongs after q, and == 0 if their
  198.  *             host and filename fields are identical.
  199.  */
  200. defcmplink(p,q)
  201.     VLINK p,q;
  202.     {
  203.     int result;
  204.  
  205.     if ((result=strcmp(p->host,q->host)) != 0)
  206.         return(result);
  207.     else
  208.         return(strcmp(p->filename,q->filename));
  209.     }
  210.  
  211. /*
  212.  * invdatecmplink: An alternative comparison function for sorting that
  213.  *               compares links p and q first by LAST-MODIFIED date,
  214.  *                 if they both have that attribute. If both links
  215.  *                 don't have that attribute or the dates are the
  216.  *                 same, it then calls defcmplink() and returns its 
  217.  *           value.
  218.  */
  219. invdatecmplink(p,q)
  220.     VLINK p,q;
  221.     {
  222.     PATTRIB pat,qat;
  223.     char *pdate,*qdate;
  224.     int result;
  225.     
  226.     pdate = qdate = NULL;
  227.     for (pat = p->lattrib; pat; pat = pat->next)
  228.         if(strcmp(pat->aname,"LAST-MODIFIED") == 0)
  229.         pdate = pat->value.ascii;
  230.     for (qat = q->lattrib; qat; qat = qat->next)
  231.         if(strcmp(qat->aname,"LAST-MODIFIED") == 0)
  232.         qdate = qat->value.ascii;
  233.     if(!pdate && !qdate) return(defcmplink(p,q));
  234.     if(!pdate) return(1); 
  235.     if(!qdate) return(-1);
  236.     if((result=strcmp(qdate,pdate)) == 0) return(defcmplink(p,q));
  237.     else return(result);
  238.     }
  239.